package cn.com.scooper.utils.sm2;


import com.alibaba.fastjson.JSONObject;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class SM2EncryptUtil {

    private static X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");

    private static ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());

    public static final String PUBLIC_KEY = "041a1571612a23c040f16be45d0bc3512f6d76aaf210174fecd1c2c055bd76614ed06d3830b612457809d8b653d4981fd4cdb1b6dc8d166146074832f565324e22";

    public static AsymCryptParam createKey() throws Exception {
        // 生成密钥对
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
        keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
        //私钥，16进制格式，自己保存，格式如a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853
        BigInteger privateKey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String privateKeyHex = privateKey.toString(16);
        //公钥，16进制格式，发给前端，格式如04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
        return new AsymCryptParam(privateKeyHex, publicKeyHex);
    }


    public static String encrypt(String str) throws Exception {
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(hexString2byte(PUBLIC_KEY));
        // 公钥前面的02或者03表示是压缩公钥，04表示未压缩公钥, 04的时候，可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
        byte[] arrayOfBytes = str.getBytes(StandardCharsets.UTF_8);
        // 原实现里没这个encode,导致和js的加密结果不对应.
        arrayOfBytes = Base64.getEncoder().encode(arrayOfBytes);
        arrayOfBytes = sm2Engine.processBlock(arrayOfBytes, 0, arrayOfBytes.length);
        return Hex.toHexString(arrayOfBytes);
    }

    /**
     * - 16进制字符串转字节数组
     * <p>
     * - @param hexString 16进制字符串    如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
     * - @return 16进制字符串转字节数组
     */
    public static byte[] hexString2byte(String hexString) {
        if (null == hexString || hexString.length() % 2 != 0 || hexString.contains("null")) {
            return null;
        }
        byte[] bytes = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff);
        }
        return bytes;
    }
}